#include "Thread.hpp"
#include <mutex>
#include <vector>

#define NUM 10
int ticketnum = 100;//票的总数
//std::mutex gmtx;


// void Ticket()
// {
//     while(true)
//     {
//         if(ticketnum > 0)
//         {
//             usleep(1000);
//             printf("get a new ticket, id: %d\n",ticketnum--);//由于ticknum--这个操作并不是原子的，会转换为3条指令，首先从内存把数据加载到寄存器中，
//             //再在寄存器中对ticknum--，最后在放回内存，其在执行某一个步骤时候，可能就会被时钟中断打断操作，导致被其他线程抢占，后面被切回来的时候，
//             //会把之前寄存器上下文重新加载进内存，导致线程切换后的线程放回内存中的值被覆盖如果不加锁，就可能导致票数减成负数，或者某一时刻票数增加
//             //usleep(10);//模拟出库
//         }
//         else
//         {
//             break;
//         }
//     }
// }

class ThreadData
{
public:
    std::string name;
    pthread_mutex_t *lock_ptr;
};

void Ticket(ThreadData& td)
{
    while (true)
    {
        //gmtx.lock();
        pthread_mutex_lock(td.lock_ptr); // 加锁
        if (ticketnum > 0)
        {
            usleep(1000);

            // 1. 抢票
            printf("get a new ticket, who get it: %s, id: %d\n", td.name.c_str(), ticketnum--);
            // gmtx.unlock();
            pthread_mutex_unlock(td.lock_ptr);
            // 2. 入库模拟
            usleep(50);
        }
        else
        {
            pthread_mutex_unlock(td.lock_ptr); 
            // gmtx.unlock();
            break;
        }
    }
}

int main()
{


    pthread_mutex_t lock;
    pthread_mutex_init(&lock,nullptr);
    std::vector<ThreadModule::Thread<std::reference_wrapper<ThreadData>>> threads;
    for (int i = 0; i < NUM; i++)
    {
        ThreadData *td = new ThreadData();
        td->lock_ptr = &lock;
        threads.emplace_back(Ticket, *td);
        td->name = threads.back().Name();
    }


    //用线程库的v1版本
    // std::vector<ThreadModule::Thread> threads;
    // for (int i = 0; i < NUM; i++)
    // {
    //     ThreadModule::Thread t(Ticket);
    //     threads.push_back(t);
    // }

    for(auto& thread:threads)
    {
        thread.Start();
    }
    
    
    for(auto& thread:threads)
    {
        thread.Join();
    }
    pthread_mutex_destroy(&lock);
    return 0;   
}